home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / plotting / gnuplot3.lzh / gnuplot / util.c < prev    next >
C/C++ Source or Header  |  1991-09-08  |  13KB  |  604 lines

  1. /* GNUPLOT - util.c */
  2. /*
  3.  * Copyright (C) 1986, 1987, 1990, 1991   Thomas Williams, Colin Kelley
  4.  *
  5.  * Permission to use, copy, and distribute this software and its
  6.  * documentation for any purpose with or without fee is hereby granted, 
  7.  * provided that the above copyright notice appear in all copies and 
  8.  * that both that copyright notice and this permission notice appear 
  9.  * in supporting documentation.
  10.  *
  11.  * Permission to modify the software is granted, but not the right to
  12.  * distribute the modified code.  Modifications are to be distributed 
  13.  * as patches to released version.
  14.  *  
  15.  * This software is provided "as is" without express or implied warranty.
  16.  * 
  17.  *
  18.  * AUTHORS
  19.  * 
  20.  *   Original Software:
  21.  *     Thomas Williams,  Colin Kelley.
  22.  * 
  23.  *   Gnuplot 2.0 additions:
  24.  *       Russell Lang, Dave Kotz, John Campbell.
  25.  *
  26.  *   Gnuplot 3.0 additions:
  27.  *       Gershon Elber and many others.
  28.  * 
  29.  * Send your comments or suggestions to 
  30.  *  pixar!info-gnuplot@sun.com.
  31.  * This is a mailing list; to join it send a note to 
  32.  *  pixar!info-gnuplot-request@sun.com.  
  33.  * Send bug reports to
  34.  *  pixar!bug-gnuplot@sun.com.
  35.  */
  36.  
  37. #include <ctype.h>
  38. #include <setjmp.h>
  39. #include <stdio.h>
  40. #include <errno.h>
  41. #include "plot.h"
  42.  
  43. BOOLEAN screen_ok;
  44.     /* TRUE if command just typed; becomes FALSE whenever we
  45.         send some other output to screen.  If FALSE, the command line
  46.         will be echoed to the screen before the ^ error message. */
  47.  
  48. #ifndef vms
  49. #ifndef __ZTC__
  50. extern int errno;
  51. extern int sys_nerr;
  52. extern char *sys_errlist[];
  53. #endif
  54. #endif /* vms */
  55.  
  56. extern char input_line[];
  57. extern struct lexical_unit token[];
  58. extern jmp_buf env;    /* from plot.c */
  59. extern int inline_num;        /* from command.c */
  60. extern BOOLEAN interactive;    /* from plot.c */
  61. extern char *infile_name;    /* from plot.c */
  62.  
  63. extern char *strchr();
  64.  
  65. #ifndef AMIGA_AC_5
  66. extern double sqrt(), atan2();
  67. #endif
  68.  
  69. /*
  70.  * chr_in_str() compares the characters in the string of token number t_num
  71.  * with c, and returns TRUE if a match was found.
  72.  */
  73. chr_in_str(t_num, c)
  74. int t_num;
  75. char c;
  76. {
  77. register int i;
  78.  
  79.     if (!token[t_num].is_token)
  80.         return(FALSE);                /* must be a value--can't be equal */
  81.     for (i = 0; i < token[t_num].length; i++) {
  82.         if (input_line[token[t_num].start_index+i] == c)
  83.             return(TRUE);
  84.         }
  85.     return FALSE;
  86. }
  87.  
  88.  
  89. /*
  90.  * equals() compares string value of token number t_num with str[], and
  91.  *   returns TRUE if they are identical.
  92.  */
  93. equals(t_num, str)
  94. int t_num;
  95. char *str;
  96. {
  97. register int i;
  98.  
  99.     if (!token[t_num].is_token)
  100.         return(FALSE);                /* must be a value--can't be equal */
  101.     for (i = 0; i < token[t_num].length; i++) {
  102.         if (input_line[token[t_num].start_index+i] != str[i])
  103.             return(FALSE);
  104.         }
  105.     /* now return TRUE if at end of str[], FALSE if not */
  106.     return(str[i] == '\0');
  107. }
  108.  
  109.  
  110.  
  111. /*
  112.  * almost_equals() compares string value of token number t_num with str[], and
  113.  *   returns TRUE if they are identical up to the first $ in str[].
  114.  */
  115. almost_equals(t_num, str)
  116. int t_num;
  117. char *str;
  118. {
  119. register int i;
  120. register int after = 0;
  121. register start = token[t_num].start_index;
  122. register length = token[t_num].length;
  123.  
  124.     if (!token[t_num].is_token)
  125.         return(FALSE);                /* must be a value--can't be equal */
  126.     for (i = 0; i < length + after; i++) {
  127.         if (str[i] != input_line[start + i]) {
  128.             if (str[i] != '$')
  129.                 return(FALSE);
  130.             else {
  131.                 after = 1;
  132.                 start--;    /* back up token ptr */
  133.                 }
  134.             }
  135.         }
  136.  
  137.     /* i now beyond end of token string */
  138.  
  139.     return(after || str[i] == '$' || str[i] == '\0');
  140. }
  141.  
  142.  
  143.  
  144. isstring(t_num)
  145. int t_num;
  146. {
  147.     
  148.     return(token[t_num].is_token &&
  149.            (input_line[token[t_num].start_index] == '\'' ||
  150.            input_line[token[t_num].start_index] == '\"'));
  151. }
  152.  
  153.  
  154. isnumber(t_num)
  155. int t_num;
  156. {
  157.     return(!token[t_num].is_token);
  158. }
  159.  
  160.  
  161. isletter(t_num)
  162. int t_num;
  163. {
  164.     return(token[t_num].is_token &&
  165.             (isalpha(input_line[token[t_num].start_index])));
  166. }
  167.  
  168.  
  169. /*
  170.  * is_definition() returns TRUE if the next tokens are of the form
  171.  *   identifier =
  172.  *        -or-
  173.  *   identifier ( identifer ) =
  174.  */
  175. is_definition(t_num)
  176. int t_num;
  177. {
  178.     return (isletter(t_num) &&
  179.             (equals(t_num+1,"=") ||            /* variable */
  180.             (equals(t_num+1,"(") &&        /* function */
  181.              isletter(t_num+2)   &&
  182.              equals(t_num+3,")") &&
  183.              equals(t_num+4,"=") ) ||
  184.             (equals(t_num+1,"(") &&        /* function with */
  185.              isletter(t_num+2)   &&        /* two variables */
  186.              equals(t_num+3,",") &&
  187.              isletter(t_num+4)   &&
  188.              equals(t_num+5,")") &&
  189.              equals(t_num+6,"=") )
  190.         ));
  191. }
  192.  
  193.  
  194.  
  195. /*
  196.  * copy_str() copies the string in token number t_num into str, appending
  197.  *   a null.  No more than MAX_ID_LEN chars are copied.
  198.  */
  199. copy_str(str, t_num)
  200. char str[];
  201. int t_num;
  202. {
  203. register int i = 0;
  204. register int start = token[t_num].start_index;
  205. register int count;
  206.  
  207.     if ((count = token[t_num].length) > MAX_ID_LEN)
  208.         count = MAX_ID_LEN;
  209.     do {
  210.         str[i++] = input_line[start++];
  211.         } while (i != count);
  212.     str[i] = '\0';
  213. }
  214.  
  215.  
  216. /*
  217.  * quote_str() does the same thing as copy_str, except it ignores the
  218.  *   quotes at both ends.  This seems redundant, but is done for
  219.  *   efficency.
  220.  */
  221. quote_str(str, t_num)
  222. char str[];
  223. int t_num;
  224. {
  225. register int i = 0;
  226. register int start = token[t_num].start_index + 1;
  227. register int count;
  228.  
  229.     if ((count = token[t_num].length - 2) > MAX_ID_LEN)
  230.         count = MAX_ID_LEN;
  231.     if (count>0) {
  232.         do {
  233.             str[i++] = input_line[start++];
  234.             } while (i != count);
  235.     }
  236.     str[i] = '\0';
  237. }
  238.  
  239.  
  240. /*
  241.  * quotel_str() does the same thing as quote_str, except it uses
  242.  * MAX_LINE_LEN instead of MAX_ID_LEN. 
  243.  */ 
  244. quotel_str(str, t_num) 
  245. char str[]; 
  246. int t_num; 
  247. {
  248. register int i = 0;
  249. register int start = token[t_num].start_index + 1;
  250. register int count;
  251.  
  252.     if ((count = token[t_num].length - 2) > MAX_LINE_LEN)
  253.         count = MAX_LINE_LEN;
  254.     if (count>0) {
  255.         do {
  256.             str[i++] = input_line[start++];
  257.             } while (i != count);
  258.     }
  259.     str[i] = '\0';
  260. }
  261.  
  262.  
  263. /*
  264.  *    capture() copies into str[] the part of input_line[] which lies between
  265.  *    the begining of token[start] and end of token[end].
  266.  */
  267. capture(str,start,end)
  268. char str[];
  269. int start,end;
  270. {
  271. register int i,e;
  272.  
  273.     e = token[end].start_index + token[end].length;
  274.     for (i = token[start].start_index; i < e && input_line[i] != '\0'; i++)
  275.         *str++ = input_line[i];
  276.     *str = '\0';
  277. }
  278.  
  279.  
  280. /*
  281.  *    m_capture() is similar to capture(), but it mallocs storage for the
  282.  *  string.
  283.  */
  284. m_capture(str,start,end)
  285. char **str;
  286. int start,end;
  287. {
  288. register int i,e;
  289. register char *s;
  290.  
  291.     if (*str)        /* previous pointer to malloc'd memory there */
  292.         free(*str);
  293.     e = token[end].start_index + token[end].length;
  294.     *str = alloc((unsigned int)(e - token[start].start_index + 1), "string");
  295.      s = *str;
  296.      for (i = token[start].start_index; i < e && input_line[i] != '\0'; i++)
  297.       *s++ = input_line[i];
  298.      *s = '\0';
  299. }
  300.  
  301.  
  302. /*
  303.  *    m_quote_capture() is similar to m_capture(), but it removes
  304.     quotes from either end if the string.
  305.  */
  306. m_quote_capture(str,start,end)
  307. char **str;
  308. int start,end;
  309. {
  310. register int i,e;
  311. register char *s;
  312.  
  313.     if (*str)        /* previous pointer to malloc'd memory there */
  314.         free(*str);
  315.     e = token[end].start_index + token[end].length-1;
  316.     *str = alloc((unsigned int)(e - token[start].start_index + 1), "string");
  317.      s = *str;
  318.     for (i = token[start].start_index + 1; i < e && input_line[i] != '\0'; i++)
  319.      *s++ = input_line[i];
  320.     *s = '\0';
  321. }
  322.  
  323.  
  324. convert(val_ptr, t_num)
  325. struct value *val_ptr;
  326. int t_num;
  327. {
  328.     *val_ptr = token[t_num].l_val;
  329. }
  330.  
  331. static char *num_to_str(r)
  332. double r;
  333. {
  334.     static i = 0;
  335.     static char s[4][20];
  336.     int j = i++;
  337.  
  338.     if ( i > 3 ) i = 0;
  339.  
  340.     sprintf( s[j], "%g", r );
  341.     if ( strchr( s[j], '.' ) == NULL &&
  342.          strchr( s[j], 'e' ) == NULL &&
  343.          strchr( s[j], 'E' ) == NULL )
  344.         strcat( s[j], ".0" );
  345.  
  346.     return s[j];
  347.  
  348. disp_value(fp,val)
  349. FILE *fp;
  350. struct value *val;
  351. {
  352.     switch(val->type) {
  353.         case INT:
  354.             fprintf(fp,"%d",val->v.int_val);
  355.             break;
  356.         case CMPLX:
  357.             if (val->v.cmplx_val.imag != 0.0 )
  358.                 fprintf(fp,"{%s, %s}",
  359.                     num_to_str(val->v.cmplx_val.real),
  360.                     num_to_str(val->v.cmplx_val.imag));
  361.             else
  362.                 fprintf(fp,"%s",
  363.                     num_to_str(val->v.cmplx_val.real));
  364.             break;
  365.         default:
  366.             int_error("unknown type in disp_value()",NO_CARET);
  367.     }
  368. }
  369.  
  370.  
  371. double
  372. real(val)        /* returns the real part of val */
  373. struct value *val;
  374. {
  375.     switch(val->type) {
  376.         case INT:
  377.             return((double) val->v.int_val);
  378.         case CMPLX:
  379.             return(val->v.cmplx_val.real);
  380.     }
  381.     int_error("unknown type in real()",NO_CARET);
  382.     /* NOTREACHED */
  383.     return((double)0.0);
  384. }
  385.  
  386.  
  387. double
  388. imag(val)        /* returns the imag part of val */
  389. struct value *val;
  390. {
  391.     switch(val->type) {
  392.         case INT:
  393.             return(0.0);
  394.         case CMPLX:
  395.             return(val->v.cmplx_val.imag);
  396.     }
  397.     int_error("unknown type in imag()",NO_CARET);
  398.     /* NOTREACHED */
  399.     return((double)0.0);
  400. }
  401.  
  402.  
  403.  
  404. double
  405. magnitude(val)        /* returns the magnitude of val */
  406. struct value *val;
  407. {
  408.     switch(val->type) {
  409.         case INT:
  410.             return((double) abs(val->v.int_val));
  411.         case CMPLX:
  412.             return(sqrt(val->v.cmplx_val.real*
  413.                     val->v.cmplx_val.real +
  414.                     val->v.cmplx_val.imag*
  415.                     val->v.cmplx_val.imag));
  416.     }
  417.     int_error("unknown type in magnitude()",NO_CARET);
  418.     /* NOTREACHED */
  419.     return((double)0.0);
  420. }
  421.  
  422.  
  423.  
  424. double
  425. angle(val)        /* returns the angle of val */
  426. struct value *val;
  427. {
  428.     switch(val->type) {
  429.         case INT:
  430.             return((val->v.int_val > 0) ? 0.0 : Pi);
  431.         case CMPLX:
  432.             if (val->v.cmplx_val.imag == 0.0) {
  433.                 if (val->v.cmplx_val.real >= 0.0)
  434.                     return(0.0);
  435.                 else
  436.                     return(Pi);
  437.             }
  438.             return(atan2(val->v.cmplx_val.imag,
  439.                      val->v.cmplx_val.real));
  440.     }
  441.     int_error("unknown type in angle()",NO_CARET);
  442.     /* NOTREACHED */
  443.     return((double)0.0);
  444. }
  445.  
  446.  
  447. struct value *
  448. complex(a,realpart,imagpart)
  449. struct value *a;
  450. double realpart, imagpart;
  451. {
  452.     a->type = CMPLX;
  453.     a->v.cmplx_val.real = realpart;
  454.     a->v.cmplx_val.imag = imagpart;
  455.     return(a);
  456. }
  457.  
  458.  
  459. struct value *
  460. integer(a,i)
  461. struct value *a;
  462. int i;
  463. {
  464.     a->type = INT;
  465.     a->v.int_val = i;
  466.     return(a);
  467. }
  468.  
  469.  
  470.  
  471. os_error(str,t_num)
  472. char str[];
  473. int t_num;
  474. {
  475. #ifdef vms
  476. static status[2] = {1, 0};        /* 1 is count of error msgs */
  477. #endif
  478.  
  479. register int i;
  480.  
  481.     /* reprint line if screen has been written to */
  482.  
  483.     if (t_num != NO_CARET) {        /* put caret under error */
  484.         if (!screen_ok)
  485.             fprintf(stderr,"\n%s%s\n", PROMPT, input_line);
  486.  
  487.         for (i = 0; i < sizeof(PROMPT) - 1; i++)
  488.             (void) putc(' ',stderr);
  489.         for (i = 0; i < token[t_num].start_index; i++) {
  490.             (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr);
  491.             }
  492.         (void) putc('^',stderr);
  493.         (void) putc('\n',stderr);
  494.     }
  495.  
  496.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  497.         (void) putc(' ',stderr);
  498.     fprintf(stderr,"%s\n",str);
  499.  
  500.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  501.         (void) putc(' ',stderr);
  502.      if (!interactive)
  503.       if (infile_name != NULL)
  504.         fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num);
  505.       else
  506.         fprintf(stderr,"line %d: ", inline_num);
  507.  
  508.  
  509. #ifdef vms
  510.     status[1] = vaxc$errno;
  511.     sys$putmsg(status);
  512.     (void) putc('\n',stderr);
  513. #else
  514. #ifdef __ZTC__
  515.     fprintf(stderr,"error number %d\n\n",errno);
  516. #else
  517.     if (errno >= sys_nerr)
  518.         fprintf(stderr, "unknown errno %d\n\n", errno);
  519.     else
  520.         fprintf(stderr,"(%s)\n\n",sys_errlist[errno]);
  521. #endif
  522. #endif
  523.  
  524.     longjmp(env, TRUE);    /* bail out to command line */
  525. }
  526.  
  527.  
  528. int_error(str,t_num)
  529. char str[];
  530. int t_num;
  531. {
  532. register int i;
  533.  
  534.     /* reprint line if screen has been written to */
  535.  
  536.     if (t_num != NO_CARET) {        /* put caret under error */
  537.         if (!screen_ok)
  538.             fprintf(stderr,"\n%s%s\n", PROMPT, input_line);
  539.  
  540.         for (i = 0; i < sizeof(PROMPT) - 1; i++)
  541.             (void) putc(' ',stderr);
  542.         for (i = 0; i < token[t_num].start_index; i++) {
  543.             (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr);
  544.             }
  545.         (void) putc('^',stderr);
  546.         (void) putc('\n',stderr);
  547.     }
  548.  
  549.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  550.         (void) putc(' ',stderr);
  551.      if (!interactive)
  552.       if (infile_name != NULL)
  553.         fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num);
  554.       else
  555.         fprintf(stderr,"line %d: ", inline_num);
  556.      fprintf(stderr,"%s\n\n", str);
  557.  
  558.     longjmp(env, TRUE);    /* bail out to command line */
  559. }
  560.  
  561. /* Lower-case the given string (DFK) */
  562. /* Done in place. */
  563. void
  564. lower_case(s)
  565.      char *s;
  566. {
  567.   register char *p = s;
  568.  
  569.   while (*p != '\0') {
  570.     if (isupper(*p))
  571.      *p = tolower(*p);
  572.     p++;
  573.   }
  574. }
  575.  
  576. /* Squash spaces in the given string (DFK) */
  577. /* That is, reduce all multiple white-space chars to single spaces */
  578. /* Done in place. */
  579. void
  580. squash_spaces(s)
  581.      char *s;
  582. {
  583.   register char *r = s;        /* reading point */
  584.   register char *w = s;        /* writing point */
  585.   BOOLEAN space = FALSE;        /* TRUE if we've already copied a space */
  586.  
  587.   for (w = r = s; *r != '\0'; r++) {
  588.      if (isspace(*r)) {
  589.         /* white space; only copy if we haven't just copied a space */
  590.         if (!space) {
  591.             space = TRUE;
  592.             *w++ = ' ';
  593.         }                /* else ignore multiple spaces */
  594.      } else {
  595.         /* non-space character; copy it and clear flag */
  596.         *w++ = *r;
  597.         space = FALSE;
  598.      }
  599.   }
  600.   *w = '\0';                /* null terminate string */
  601. }
  602.  
  603.